﻿// ===============================================================================
// XCI.NET 西安交通信息WinForm开发框架 2018 版权所有
// ===============================================================================
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using XCI.Core;
using XCI.Helper;

namespace XCI.Data.Entity
{
    /// <summary>
    /// 实体数据帮助类
    /// </summary>
    public static class EntityHelper
    {
        #region 私有字段

        private static readonly StaticCache<Type, EntityData> Cache = new StaticCache<Type, EntityData>();

        #endregion

        #region Public

        /// <summary>
        /// 使用指定的实体类型获取实体数据
        /// </summary>
        /// <param name="type">实体类型</param>
        /// <returns>返回实体数据</returns>
        public static EntityData Get(Type type)
        {
            return Cache.Get(type, () => GetInternal(type));
        }

        /// <summary>
        /// 使用指定的实体类型获取实体数据
        /// </summary>
        /// <typeparam name="T">实体类型</typeparam>
        /// <returns>返回实体数据</returns>
        public static EntityData Get<T>()
        {
            return Get(typeof(T));
        }

        /// <summary>
        /// 获取Excel文件表头
        /// </summary>
        /// <typeparam name="T">实体类型</typeparam>
        /// <returns>获取导出Excel文件表头</returns>
        public static List<ExcelHead> GetExcelHeader<T>()
        {
            var meta = Get(typeof(T));
            var header = new List<ExcelHead>();
            foreach (KeyValuePair<string, EntityColumn> item in meta.AllColumns)
            {
                if (!item.Value.Export)
                {
                    continue;
                }

                var caption = item.Value.Caption;
                if (string.IsNullOrEmpty(caption))
                {
                    caption = item.Value.Name;
                }
                header.Add(new ExcelHead(item.Value.Name, caption,item.Value.Property.Property.PropertyType));
            }
            return header;
        }

        #endregion

        #region Private

        private static EntityData GetInternal(Type type)
        {
            var data = new EntityData();
            data.AllColumns = new Dictionary<string, EntityColumn>();
            data.EntityType = type;
            data.IgnoreColumns = new Dictionary<string, EntityColumn>();
            data.DbColumns = new Dictionary<string, EntityColumn>();

            #region Table

            data.TableAttr = ObjectHelper.GetAttribute<TableAttribute>(type) ?? new TableAttribute(type.Name);
            if (string.IsNullOrWhiteSpace(data.TableAttr.Name))
            {
                data.TableAttr.Name = type.Name;
            }
            if (string.IsNullOrWhiteSpace(data.TableAttr.DbName))
            {
                data.TableAttr.DbName = type.Name;
            }

            #endregion

            foreach (var property in type.GetProperties())
            {
                var column = GetColumn(property);

                #region PrimaryAttribute

                var pkAttr = ObjectHelper.GetAttribute<PrimaryAttribute>(property);
                if (pkAttr != null)
                {
                    data.PrimaryAttr = pkAttr;
                    data.PrimaryProperty = column;
                }

                #endregion

                #region ParentAttribute

                var parentAttr = ObjectHelper.GetAttribute<ParentAttribute>(property);
                if (parentAttr != null)
                {
                    data.ParentProperty = column;
                }

                #endregion

                #region PathAttribute

                var pathAttr = ObjectHelper.GetAttribute<PathAttribute>(property);
                if (pathAttr != null)
                {
                    data.PathProperty = column;
                }

                #endregion

                #region IgnoreAttribute

                var ignoreAttr = ObjectHelper.GetAttribute<IgnoreAttribute>(property);
                if (ignoreAttr != null)
                {
                    data.IgnoreColumns.Add(column.Name, column);
                }
                else
                {
                    data.DbColumns.Add(column.Name, column);
                }

                #endregion

                data.AllColumns.Add(column.Name, column);
            }
            //if (data.PrimaryAttr == null)
            //{
            //    data.PrimaryAttr = new PrimaryAttribute();
            //}
            return data;
        }

        private static EntityColumn GetColumn(PropertyInfo pinfo)
        {
            var col = new EntityColumn();
            col.Name = pinfo.Name;
            col.DbName = pinfo.Name;
            col.Export = true;
            col.Visable = true;
            col.Property = new FastProperty(pinfo);

            var colAttr = ObjectHelper.GetAttribute<ColumnAttribute>(pinfo);
            if (colAttr == null) return col;

            col.Export = colAttr.Export;
            col.Visable = colAttr.Visable;
            if (!string.IsNullOrWhiteSpace(colAttr.DbName))
            {
                col.DbName = colAttr.DbName;
            }
            if (!string.IsNullOrWhiteSpace(colAttr.Caption))
            {
                col.Caption = colAttr.Caption;
            }
            return col;
        }

        #endregion
    }
}